package com.tyros.common.kit.bean;

import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.tyros.common.kit.log.LogKit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Bean属性拷贝
 *
 * @author zhangshuaiyin
 * @date 2022/1/15 22:17
 */
@Slf4j
public class BeanCopyKit {
    public static <T> T copy(Object source, Class<T> target) {
        if (Objects.isNull(source)) {
            return null;
        }
        T obj = null;
        try {
            obj = target.newInstance();
            BeanUtils.copyProperties(source, obj);
        } catch (Exception e) {
            log.error("属性拷贝出现异常", e);
        }
        return obj;
    }

    public static <T> List<T> copyList(List<?> sources, Class<T> target) {
        if (Objects.isNull(sources) || sources.isEmpty()) {
            return Collections.emptyList();
        }
        return sources.stream().map(obj -> copy(obj, target)).collect(Collectors.toList());
    }

    /**
     * 将源对象不为空属性填充到目标对象同名为空属性上
     *
     * @param source 源对象
     * @param target 目标对象
     */
    public static void fill(Object source, Object target) {
        List<Field> entityFields = ReflectionKit.getFieldList(source.getClass());
        List<Field> dtoFields = ReflectionKit.getFieldList(target.getClass());
        entityFields.forEach(field -> {
            Object value = ReflectionKit.getFieldValue(source, field.getName());
            if (Objects.isNull(value)) {
                return;
            }
            Optional<Field> find = dtoFields.stream().filter(field1 -> fieldEquals(field1, field)
                    && ReflectionKit.getFieldValue(target, field1.getName()) == null).findAny();
            if (find.isPresent()) {
                Method method = ReflectionUtils.findMethod(target.getClass(), getSetMethodName(field.getName()), field.getType());
                //method.setAccessible(true);
                try {
                    assert method != null;
                    method.invoke(target, value);
                } catch (Exception e) {
                    LogKit.error(log, "回写属性失败:{}", e);
                }
            }
        });
    }

    /**
     * 获取 setter 方法名
     *
     * @param fieldName 属性名
     * @return setter 方法名
     */
    public static String getSetMethodName(final String fieldName) {
        return StringUtils.concatCapitalize("set", fieldName);
    }

    /**
     * 判断两个属性名是否相等
     *
     * @param source 属性
     * @param target 属性
     * @return 是否相等
     */
    public static boolean fieldEquals(Field source, Field target) {
        return source.getName().equals(target.getName()) && source.getType() == target.getType();
    }
}
